#include <string>
#include <sstream>

#include "tcpsocket.h"

TCPSocket::TCPSocket():
    sockfd(-1) {
}

TCPSocket::TCPSocket(int sockfd):
	sockfd(sockfd) {
}

TCPSocket::TCPSocket(const TCPSocket& sock) {
	this->sockfd = sock.sockfd;
}

TCPSocket& TCPSocket::operator=(const TCPSocket& sock) {
	this->sockfd = sock.sockfd;
}

bool TCPSocket::listen(int port, int backlog) {
	struct sockaddr_in	serv_addr;

/* 1 Inicializar la estructura del socket:
 * 	bzero(): borrar la estructura
 * 	htonl(): Host-TO-Network Long integer (Byte order)
 * 	htons(): Host-TO-Network Short integer (Byte order)
 */

/* 1.1 inicializar la estructura con ceros. */
	bzero((char *) &serv_addr, sizeof(serv_addr));
/* 1.2 familia protocolos TCP/IP. */
	serv_addr.sin_family = AF_INET;
/* 1.3 cualquier cliente. */
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
/* 1.4 port en formato red. */
	serv_addr.sin_port = htons((u_short)port);

/* 2 Crear un socket para TCP (un Internet stream socket). */
	if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
	    return false;
	}

/* 3 Vincular el socket con la direccion local. */
	if( bind( sockfd,(struct sockaddr*) &serv_addr,sizeof(serv_addr)) < 0) {
		return false; /* error: no se puede hacer el bind */
	}

/* 4 Definir la cola de espera para backlog clientes */
	if( ::listen(sockfd, backlog) < 0) {
		return false; /* error: no se puede configurar la cola de espera. */
	}

	return true;
}

bool TCPSocket::connect(const std::string& server, int port) {
	struct sockaddr_in 	serv_addr;
	struct hostent 		*ptr_server; 	/* direcci�n IP del server */

/* 1 Inicializar la estructura del socket:
 * 	bzero(): borrar la estructura
 * 	htonl(): Host-TO-Network Long integer (Byte order)
 * 	htons(): Host-TO-Network Short integer (Byte order)
 */

/* 1.1 Inicializar la estructura con ceros. */
	bzero((char *) &serv_addr, sizeof(serv_addr));
/* 1.2 Familia protocolos TCP/IP */
	serv_addr.sin_family      = AF_INET;
/* 1.3 Cargar port en el socket. */
	serv_addr.sin_port        = htons(port);
/* 1.4 Cargar direccion del server en el socket. */
	ptr_server = gethostbyname(server.c_str());
	if( ((char*)ptr_server) == NULL ) {
		return false; /* error: no se encontr� el servidor */
	}
	memcpy(&serv_addr.sin_addr, ptr_server->h_addr, ptr_server->h_length);

/* 2 Crear un socket para TCP (un Internet stream socket). */
	if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
	    return false;
	}

/* 3 Connectarse al server. */
	if(::connect(sockfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr)) < 0) {
		return false; /* error: no se puede conectar */
	}

	return true;
}

int TCPSocket::get_fd() {
	return sockfd;
}

TCPSocket TCPSocket::accept() {
	TCPSocket newsocket;
	int newsockfd;
	struct sockaddr_in cli_addr;
	unsigned clilen;

	clilen = sizeof(cli_addr);
	newsockfd = ::accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);

	return TCPSocket(newsockfd);
}

void TCPSocket::close() {
	::close(sockfd);
	sockfd = -1;
}

TCPSocket::operator bool() {
	return sockfd != -1;
}
